package dcm4chee

import (
	"encoding/json"
	"errors"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strconv"
)

type DicomCount struct {
	Count int `json:"count"`
}
type Connector struct {
	url  url.URL
	aets string
}

func NewConnector(host string, aets string) *Connector {
	return &Connector{
		url:  url.URL{Scheme: "http", Host: host},
		aets: aets}
}

func (r *Connector) CountStudies() int {
	params := url.Values{}
	params.Add("includefield", "all")

	urlData := r.url
	urlData.Path = fmt.Sprintf("dcm4chee-arc/aets/%s/rs/studies/count", r.aets)
	urlData.RawQuery = params.Encode()

	urlStr := urlData.String()

	if resp, err := http.Get(urlStr); err != nil {
		return -1

	} else {
		defer resp.Body.Close()

		var count DicomCount

		if body, err := ioutil.ReadAll(resp.Body); err != nil {
			return -2
		} else if err = json.Unmarshal(body, &count); err != nil {
			return -3
		}
		return count.Count
	}
}
func (r *Connector) CountSeries(studiesId string) int {
	params := url.Values{}
	params.Add("includefield", "all")

	u := r.url
	u.Path = fmt.Sprintf("dcm4chee-arc/aets/%s/rs/studies/%s/series/count", r.aets, studiesId)
	u.RawQuery = params.Encode()

	urlStr := u.String()

	if resp, err := http.Get(urlStr); err != nil {
		return -1

	} else {
		defer resp.Body.Close()

		var count DicomCount

		if body, err := ioutil.ReadAll(resp.Body); err != nil {
			return -2
		} else if err = json.Unmarshal(body, &count); err != nil {
			return -3
		}
		return count.Count
	}
}
func (r *Connector) CountInstances(studiesId, seriesId string) int {
	params := url.Values{}
	params.Add("includefield", "all")
	urlData := r.url
	urlData.Path = fmt.Sprintf("dcm4chee-arc/aets/%s/rs/studies/%s/series/%s/instances/count", r.aets, studiesId, seriesId)
	urlData.RawQuery = params.Encode()

	urlStr := urlData.String()

	if resp, err := http.Get(urlStr); err != nil {
		return -1

	} else {
		defer resp.Body.Close()

		var count DicomCount

		if body, err := ioutil.ReadAll(resp.Body); err != nil {
			return -2
		} else if err = json.Unmarshal(body, &count); err != nil {
			return -3
		}
		return count.Count
	}
}

func (r *Connector) GetStudiesFromOffset(offset, limit int) (data []map[string]DicomItem, err error) {
	params := url.Values{}
	if limit > 0 {
		params.Add("limit", strconv.Itoa(limit))
	}
	if offset > 0 {
		params.Add("offset", strconv.Itoa(offset))
	}
	params.Add("includefield", "all")

	u := r.url
	u.Path = fmt.Sprintf("dcm4chee-arc/aets/%s/rs/studies", r.aets)
	u.RawQuery = params.Encode()

	return getResponse(u.String())
}

func (r *Connector) GetStudiesMetadata(studiesId string) (metadata map[string]DicomItem, err error) {
	// /dcm4chee-arc/aets/AS_RECEIVED/rs/studies/1.2.276.0.26.1.1.1.2.2020.366.12384.1554382/metadata
	params := url.Values{}
	u := r.url
	u.Path = fmt.Sprintf("/dcm4chee-arc/aets/%s/rs/studies/%s/metadata", r.aets, studiesId)
	u.RawQuery = params.Encode()

	data, err := getResponse(u.String())
	if err != nil {
		return nil, err
	} else {
		return data[0], nil
	}
}

func (r *Connector) GetSeriesData(studiesId string, offset, limit int) (data []map[string]DicomItem, err error) {
	params := url.Values{}
	if limit > 0 {
		params.Add("limit", strconv.Itoa(limit))
	}
	if offset > 0 {
		params.Add("offset", strconv.Itoa(offset))
	}
	params.Add("includefield", "all")
	params.Add("orderby", "SeriesNumber")
	u := r.url
	u.Path = fmt.Sprintf("/dcm4chee-arc/aets/%s/rs/studies/%s/series", r.aets, studiesId)
	u.RawQuery = params.Encode()

	return getResponse(u.String())
}
func (r *Connector) GetInstancesData(studiesId, seriesId string, offset, limit int) (data []map[string]DicomItem, err error) {
	params := url.Values{}
	if limit > 0 {
		params.Add("limit", strconv.Itoa(limit))
	}
	if offset > 0 {
		params.Add("offset", strconv.Itoa(offset))
	}
	params.Add("includefield", "all")
	params.Add("orderby", "SeriesNumber")
	u := r.url
	u.Path = fmt.Sprintf("/dcm4chee-arc/aets/%s/rs/studies/%s/series/%s/instances", r.aets, studiesId, seriesId)
	u.RawQuery = params.Encode()

	return getResponse(u.String())
}

func (r *Connector) GetInstanceMetadata(studiesId, seriesId, instanceId string) (data map[string]DicomItem, err error) {
	u := r.url
	u.Path = fmt.Sprintf(
		"/dcm4chee-arc/aets/%s/rs/studies/%s/series/%s/instances/%s/metadata",
		r.aets, studiesId, seriesId, instanceId)
	resp, err := getResponse(u.String())
	if err != nil {
		return nil, err
	}
	if len(resp) != 1 {
		return nil, fmt.Errorf("invalid metadata object count: %d", len(resp))
	}
	return resp[0], nil
}

func getResponse(u string) (data []map[string]DicomItem, err error) {
	if resp, err := http.Get(u); err != nil {
		return nil, err

	} else {
		defer resp.Body.Close()

		if body, err := ioutil.ReadAll(resp.Body); err != nil {
			return nil, err
		} else if err = json.Unmarshal(body, &data); err != nil {
			return nil, err
		} else {
			return data, nil
		}
	}
}
func QueryDataString(data map[string]DicomItem, code string) (result string, err error) {
	if code == "" || len(code) != 8 {
		return "", errors.New("error code")
	}

	if d, ok := data[code]; !ok {
		return "", errors.New("do not have this content")
	} else {
		return d.GetString()
	}
}
func QueryDataInt(data map[string]DicomItem, code string) (result int, err error) {
	if code == "" || len(code) != 8 {
		return 0, errors.New("error code")
	}

	if d, ok := data[code]; !ok {
		return 0, errors.New("do not have this content")
	} else {
		return d.GetInt()

	}
}
